#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <inttypes.h>
#include <errno.h>

#define PORT 8080
#define BUFFER_SIZE 4096
#define MAX_FILENAME_LEN 256
#define MAX_USERS 10
#define MD5_DIGEST_LENGTH 16

// 用户认证信息
typedef struct {
    char username[32];
    char password[32];
} User;

// 文件信息结构
typedef struct {
    char filename[MAX_FILENAME_LEN];
    size_t file_size;
    uint8_t md5[MD5_DIGEST_LENGTH];
    FILE* file_handle;
} FileInfo;

// 服务器状态
typedef struct {
    int client_connected;
    int authenticated;
    User users[MAX_USERS];
    int user_count;
} ServerState;

// 初始化服务器状态
void init_server(ServerState* server) {
    server->client_connected = 0;
    server->authenticated = 0;
    server->user_count = 0;
    
    // 添加测试用户
    strcpy(server->users[server->user_count].username, "admin");
    strcpy(server->users[server->user_count].password, "password");
    server->user_count++;
    
    strcpy(server->users[server->user_count].username, "user");
    strcpy(server->users[server->user_count].password, "123456");
    server->user_count++;
}

// 简单的MD5计算（实际应用中应使用真正的MD5库）
void calculate_md5(const char* filename, uint8_t* md5_digest) {
    // 简化实现：使用文件名和文件大小的组合作为"MD5"
    // 实际应用中应使用真正的MD5算法
    struct stat st;
    if (stat(filename, &st) == 0) {
        // 基于文件名和文件大小生成伪MD5
        unsigned long hash = 5381;
        const char* p = filename;
        while (*p) {
            hash = ((hash << 5) + hash) + *p;
            p++;
        }
        hash += st.st_size;
        
        // 填充MD5数组
        for (int i = 0; i < MD5_DIGEST_LENGTH; i++) {
            md5_digest[i] = (hash >> (i * 8)) & 0xFF;
        }
    } else {
        // 文件不存在，填充零
        memset(md5_digest, 0, MD5_DIGEST_LENGTH);
    }
}

// 序列化字符串（长度前缀法）
int serialize_string(const char* str, uint8_t* buffer, size_t buffer_size) {
    size_t len = strlen(str);
    if (len + sizeof(uint32_t) > buffer_size) {
        return -1;
    }
    
    uint32_t net_len = htonl((uint32_t)len);
    memcpy(buffer, &net_len, sizeof(net_len));
    memcpy(buffer + sizeof(net_len), str, len);
    
    return sizeof(net_len) + len;
}

// 反序列化字符串
int deserialize_string(const uint8_t* buffer, char* str, size_t str_size) {
    uint32_t net_len;
    memcpy(&net_len, buffer, sizeof(net_len));
    size_t len = ntohl(net_len);
    
    if (len >= str_size) {
        return -1;
    }
    
    memcpy(str, buffer + sizeof(net_len), len);
    str[len] = '\0';
    
    return sizeof(net_len) + len;
}

// 用户认证
int authenticate_user(ServerState* server, const char* username, const char* password) {
    for (int i = 0; i < server->user_count; i++) {
        if (strcmp(server->users[i].username, username) == 0 &&
            strcmp(server->users[i].password, password) == 0) {
            return 1;
        }
    }
    return 0;
}

// 处理登录请求
int handle_login(int client_sock, ServerState* server) {
    uint8_t buffer[BUFFER_SIZE];
    int bytes_received = recv(client_sock, buffer, BUFFER_SIZE, 0);
    
    if (bytes_received <= 0) {
        return -1;
    }
    
    char username[32];
    char password[32];
    int offset = 0;
    
    // 反序列化用户名
    int username_len = deserialize_string(buffer + offset, username, sizeof(username));
    if (username_len < 0) {
        return -1;
    }
    offset += username_len;
    
    // 反序列化密码
    int password_len = deserialize_string(buffer + offset, password, sizeof(password));
    if (password_len < 0) {
        return -1;
    }
    
    printf("登录尝试: 用户名=%s, 密码=%s\n", username, password);
    
    // 验证用户
    if (authenticate_user(server, username, password)) {
        server->authenticated = 1;
        printf("用户 %s 登录成功\n", username);
        
        // 发送成功响应
        uint8_t response = 1;
        send(client_sock, &response, 1, 0);
        return 1;
    } else {
        printf("用户 %s 登录失败\n", username);
        
        // 发送失败响应
        uint8_t response = 0;
        send(client_sock, &response, 1, 0);
        return 0;
    }
}

// 处理文件信息请求
int handle_file_info(int client_sock) {
    uint8_t buffer[BUFFER_SIZE];
    int bytes_received = recv(client_sock, buffer, BUFFER_SIZE, 0);
    
    if (bytes_received <= 0) {
        return -1;
    }
    
    char filename[MAX_FILENAME_LEN];
    deserialize_string(buffer, filename, sizeof(filename));
    
    printf("文件信息请求: %s\n", filename);
    
    // 检查文件是否存在
    struct stat st;
    if (stat(filename, &st) != 0) {
        printf("文件不存在: %s\n", filename);
        
        // 发送错误响应（文件大小设为0）
        uint8_t response[BUFFER_SIZE];
        int offset = 0;
        
        // 序列化文件名
        int filename_len = serialize_string(filename, response + offset, BUFFER_SIZE - offset);
        offset += filename_len;
        
        // 文件大小设为0
        uint64_t net_file_size = htobe64(0);
        memcpy(response + offset, &net_file_size, sizeof(net_file_size));
        offset += sizeof(net_file_size);
        
        // MD5设为全零
        uint8_t zero_md5[MD5_DIGEST_LENGTH] = {0};
        memcpy(response + offset, zero_md5, MD5_DIGEST_LENGTH);
        offset += MD5_DIGEST_LENGTH;
        
        send(client_sock, response, offset, 0);
        return 0;
    }
    
    // 计算文件MD5
    uint8_t md5_digest[MD5_DIGEST_LENGTH];
    calculate_md5(filename, md5_digest);
    
    // 准备响应
    uint8_t response[BUFFER_SIZE];
    int offset = 0;
    
    // 序列化文件名
    int filename_len = serialize_string(filename, response + offset, BUFFER_SIZE - offset);
    offset += filename_len;
    
    // 序列化文件大小
    uint64_t net_file_size = htobe64(st.st_size);
    memcpy(response + offset, &net_file_size, sizeof(net_file_size));
    offset += sizeof(net_file_size);
    
    // 序列化MD5
    memcpy(response + offset, md5_digest, MD5_DIGEST_LENGTH);
    offset += MD5_DIGEST_LENGTH;
    
    // 发送响应
    if (send(client_sock, response, offset, 0) < 0) {
        perror("发送文件信息失败");
        return -1;
    }
    
    printf("发送文件信息: %s (%ld bytes)\n", filename, st.st_size);
    return 1;
}

// 处理文件块请求
int handle_file_chunk(int client_sock) {
    uint8_t buffer[BUFFER_SIZE];
    int bytes_received = recv(client_sock, buffer, BUFFER_SIZE, 0);
    
    if (bytes_received <= 0) {
        return -1;
    }
    
    int offset = 0;
    char filename[MAX_FILENAME_LEN];
    
    // 反序列化文件名
    int filename_len = deserialize_string(buffer + offset, filename, sizeof(filename));
    offset += filename_len;
    
    // 反序列化偏移量
    uint64_t net_offset;
    memcpy(&net_offset, buffer + offset, sizeof(net_offset));
    uint64_t file_offset = be64toh(net_offset);
    offset += sizeof(net_offset);
    
    // 反序列化块大小
    uint64_t net_chunk_size;
    memcpy(&net_chunk_size, buffer + offset, sizeof(net_chunk_size));
    uint64_t chunk_size = be64toh(net_chunk_size);
    
    printf("文件块请求: %s (偏移: %" PRIu64 ", 大小: %" PRIu64 ")\n", 
           filename, file_offset, chunk_size);
    
    // 打开文件
    FILE* file = fopen(filename, "rb");
    if (!file) {
        perror("打开文件失败");
        
        // 发送错误响应
        uint64_t net_offset_resp = htobe64(file_offset);
        uint64_t net_size_resp = htobe64(0);
        send(client_sock, &net_offset_resp, sizeof(net_offset_resp), 0);
        send(client_sock, &net_size_resp, sizeof(net_size_resp), 0);
        return 0;
    }
    
    // 定位到指定偏移量
    if (fseek(file, file_offset, SEEK_SET) != 0) {
        perror("文件定位失败");
        fclose(file);
        
        // 发送错误响应
        uint64_t net_offset_resp = htobe64(file_offset);
        uint64_t net_size_resp = htobe64(0);
        send(client_sock, &net_offset_resp, sizeof(net_offset_resp), 0);
        send(client_sock, &net_size_resp, sizeof(net_size_resp), 0);
        return 0;
    }
    
    // 计算实际可读取的大小
    struct stat st;
    fstat(fileno(file), &st);
    uint64_t actual_chunk_size = chunk_size;
    if (file_offset + chunk_size > st.st_size) {
        actual_chunk_size = st.st_size - file_offset;
    }
    
    // 发送响应头
    uint64_t net_offset_resp = htobe64(file_offset);
    uint64_t net_size_resp = htobe64(actual_chunk_size);
    
    if (send(client_sock, &net_offset_resp, sizeof(net_offset_resp), 0) < 0 ||
        send(client_sock, &net_size_resp, sizeof(net_size_resp), 0) < 0) {
        perror("发送响应头失败");
        fclose(file);
        return -1;
    }
    
    // 发送文件内容
    size_t bytes_sent_total = 0;
    while (bytes_sent_total < actual_chunk_size) {
        size_t to_read = actual_chunk_size - bytes_sent_total;
        if (to_read > BUFFER_SIZE) {
            to_read = BUFFER_SIZE;
        }
        
        size_t bytes_read = fread(buffer, 1, to_read, file);
        if (bytes_read == 0) {
            break;
        }
        
        if (send(client_sock, buffer, bytes_read, 0) < 0) {
            perror("发送文件内容失败");
            break;
        }
        
        bytes_sent_total += bytes_read;
        
        // 显示进度
        int progress = (int)((double)bytes_sent_total / actual_chunk_size * 100);
        printf("\r发送进度: %d%%", progress);
        fflush(stdout);
    }
    
    printf("\n文件块发送完成\n");
    fclose(file);
    return 1;
}

// 处理客户端请求
void handle_client(int client_sock, ServerState* server) {
    printf("客户端连接成功\n");
    server->client_connected = 1;
    
    // 处理登录
    if (handle_login(client_sock, server) <= 0) {
        printf("登录失败或连接错误\n");
        return;
    }
    
    // 主循环：处理文件请求
    while (1) {
        // 接收请求类型
        uint8_t request_type;
        int bytes_received = recv(client_sock, &request_type, 1, 0);
        
        if (bytes_received <= 0) {
            printf("客户端断开连接或错误\n");
            break;
        }
        
        switch (request_type) {
            case 1: // 文件信息请求
                handle_file_info(client_sock);
                break;
                
            case 2: // 文件块请求
                handle_file_chunk(client_sock);
                break;
                
            case 0: // 退出
                printf("客户端请求退出\n");
                break;
                
            default:
                printf("未知请求类型: %d\n", request_type);
                break;
        }
        
        if (request_type == 0) {
            break; // 退出循环
        }
    }
    
    server->client_connected = 0;
    server->authenticated = 0;
    printf("客户端处理完成\n");
}

int main() {
    int server_fd, client_sock;
    struct sockaddr_in address;
    int opt = 1;
    int addrlen = sizeof(address);
    ServerState server;
    
    // 初始化服务器状态
    init_server(&server);
    
    // 创建套接字
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }
    
    // 设置套接字选项
    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {
        perror("setsockopt");
        exit(EXIT_FAILURE);
    }
    
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(PORT);
    
    // 绑定套接字
    if (bind(server_fd, (struct sockaddr*)&address, sizeof(address)) < 0) {
        perror("bind failed");
        exit(EXIT_FAILURE);
    }
    
    // 监听
    if (listen(server_fd, 1) < 0) { // 只允许一个客户端排队
        perror("listen");
        exit(EXIT_FAILURE);
    }
    
    printf("无状态文件服务器启动，监听端口 %d\n", PORT);
    printf("支持的用户:\n");
    for (int i = 0; i < server.user_count; i++) {
        printf("  - %s / %s\n", server.users[i].username, server.users[i].password);
    }
    
    while (1) {
        // 接受连接（只支持一个客户端）
        if ((client_sock = accept(server_fd, (struct sockaddr*)&address, (socklen_t*)&addrlen)) < 0) {
            perror("accept");
            continue;
        }
        
        // 处理客户端请求
        handle_client(client_sock, &server);
        
        close(client_sock);
        printf("等待新的客户端连接...\n");
    }
    
    return 0;
}